import { _decorator, Component, Node } from 'cc';
import { DataToUiEvent } from './DataToUiEvent';
const { ccclass, property } = _decorator;

@ccclass('GEvent')
export class GEvent extends Component {
    //
    private static Max_HandlerIndex:number = 100000;

    //
    private EVENT_DEBUG:number = 0;
    //
    private sCurrEve:string;
    //
    private nCurrEveMaxIndex:number;
    //
    private nCurrEveStartIndex:number;
    //
    private tListenerHandleIndex:{[key:string]:number[];} = {};
    //当前系统环境的数量
    private nCurrEveIndex:number = 0;
    //100,000 以下的是 系统保留
    private nListenerHandleIndex:number = 0;
    //
    private nListenerForwardHandleIndex:number = 0;

    private listeners:{[key:string]:{[key:number]:any[]}};
    private forwardListeners:{[key:string]:{[key:number]:any[]}};
    private checkEventData:{[key:string]:string};
    private isDebug:boolean = false;

    
    // interface goodStu{
    //     id:number
    // }
    // interface badStu{
    //     age:number
    // }

    /**
     * https://www.coder.work/article/7633182
     * key 为 string, value 为 string
     * private dic:{[key:string]:number;} = {key1:123};
     private dic:{[key:string]:string;} = {key1:"123"};

     //添加 key, value
     dic['b'] = "2";
     dic.c = 3;

    //遍历
    for(const key in this.dic){
        if(this.dic.hasOwnProperty(key)){
            console.log(this.dic[key]);
        }
    }
     */

    //构造时传入事件名与是否冒泡参数,最后一个参数是事件附加信息
    constructor(){
        super();
        this.listeners = {};
        // 事件重定向 0只发送给拦截者一次有效  1优先发送一次有效  2只发送给拦截者始终有效 3优先发送始终有效
        this.forwardListeners = {};
        this.isDebug = false;
        //
        if(this.EVENT_DEBUG > 0){
            this.checkEventData = {};
        }
    }
    
    /**
     * 主动移除重定向事件
     * @param handleToRemove 
     */
    public removeForwardEventListener(handleToRemove:any):void{
        var isFound = false;
        for(const eventName in this.forwardListeners){
            var listenersForGEvent = this.forwardListeners[eventName];
            for(const handle in listenersForGEvent){
                if(handle == handleToRemove){
                    listenersForGEvent[handle] = null;
                    isFound = true;
                }
            }
            //
            if(isFound){
                break;
            }
        }
    }

    /**
     * 重定向事件
     * @param eventName 
     * @param listenner 
     * @param tag 为有效次数
     */
    public addForwardEventListener(eventName:string, listener:any, tag:number):number{
        //
        if(!this.forwardListeners.hasOwnProperty(eventName)){
            this.forwardListeners[eventName] = {};
        }
        //
        this.nListenerHandleIndex++;
        this.forwardListeners[eventName][this.nListenerHandleIndex] = [listener, tag];
        //
        return this.nListenerHandleIndex;
    }

    /**
     * 设置事件环境
     * @param eventName 
     */
    public setListenerHandleEve(eventName:string):void{
        if(null != eventName){
            if(!this.tListenerHandleIndex.hasOwnProperty(eventName)){
                this.nCurrEveIndex++;
                var eventId = this.nCurrEveIndex * GEvent.Max_HandlerIndex;
                this.nCurrEveStartIndex = eventId;
                this.nCurrEveMaxIndex = eventId;
                //设置起始值 //设置当前值
                this.tListenerHandleIndex[eventName] = [this.nCurrEveStartIndex, this.nCurrEveMaxIndex];
            }else{
                this.nCurrEveStartIndex = this.tListenerHandleIndex[eventName][0];
                this.nCurrEveMaxIndex = this.tListenerHandleIndex[eventName][1];
            }
        }else{
            this.nCurrEveStartIndex = 0;
            this.nCurrEveMaxIndex = 0;
        }
        this.sCurrEve = eventName;
    }
    /**
     * 重置某个环境的事件id
     * @param evetName 
     */
    public resetListenerHandleEve(eventName:string):void{
        if(null != eventName){
            if(this.tListenerHandleIndex.hasOwnProperty(eventName)){
                var nStartIndex = this.tListenerHandleIndex[eventName][0];
                //TODO .. 清除对应的所有事件
                this.tListenerHandleIndex[eventName][1] = nStartIndex;
            }
        }
    }
    /**
     * 添加监听
     * @param eventName 
     * @param listener 
     * @param tag 
     * @returns 
     */
    public addEventListener(eventName:string, listener:any, tagToRemove:any=null):string{
        //
        if(!this.listeners.hasOwnProperty(eventName)){
            this.listeners[eventName] = {};
        }
        //
        var index = 0;
        if(this.sCurrEve){
            this.nCurrEveMaxIndex++;
            if(this.nCurrEveMaxIndex - this.nCurrEveStartIndex > 9999){
                console.warn("[GEvent] addEventListener Index >= 9999");
                this.nCurrEveMaxIndex = this.nCurrEveStartIndex;
            }
            index = this.nCurrEveMaxIndex;
            this.tListenerHandleIndex[this.sCurrEve][1]  = this.nCurrEveMaxIndex;
        }else{
            this.nListenerHandleIndex++;
            if(this.nListenerHandleIndex >= GEvent.Max_HandlerIndex){
                console.log(`[GEvent] addEventListener listenerHandleIndex >= ${GEvent.Max_HandlerIndex}`);
                this.nListenerHandleIndex = 1;
            }
            index = this.nListenerHandleIndex;
        }
        //
        if(this.EVENT_DEBUG > 0){
            this.checkEventData[index] = eventName;
        }
        //
        this.listeners[eventName][index] = [listener, tagToRemove];
        return index.toString();
    }
    /**
     * 派发事件
     * @param eventName 
     * @param args 
     */
    public dispatchEvent(eventName:string, e:DataToUiEvent):void{
        //arg.join(" ");
        var isReturn:boolean = false;
        //优先判断是否需要拦截
        if(this.forwardListeners.hasOwnProperty(eventName)){
            var listenerList = this.forwardListeners[eventName];
            for(const handleIndex in listenerList){
                var arr = listenerList[handleIndex];
                var listener = arr[0];
                var tag = arr[1];
                if(tag < 2){
                    delete this.forwardListeners[eventName][handleIndex];
                }
                //
                if(0 == tag || 2 == tag){
                    isReturn = true;
                }
                //
                if(listener){
                    listener(e);
                }
            }
        }
        //
        if(isReturn){
            return;
        }
        //
        if(!this.listeners.hasOwnProperty(eventName)){
            return;
        }
        //
        // var dic = this.listeners[eventName];
        // dic.array.forEach(element => {
        //     ever
        // });
        var dic = this.listeners[eventName];
        for(var handleIndex in dic){
            //如果存在环境 则只发保留的事件 和 当前环境下的事件
            // var index = Number(handleIndex);
            // if(index < GEvent.Max_HandlerIndex || (this.sCurrEve && index <= this.nCurrEveMaxIndex && index >= this.nCurrEveStartIndex)){
                var arr = dic[handleIndex];
                if(arr[0]){
                    arr[0](e);
                }else{
                    console.error(`[GEvent] 消息无效 handleIndex=${handleIndex},sCurrEve=${this.sCurrEve},nCurrEveMaxIndex=${this.nCurrEveMaxIndex},nCurrEveStartIndex=${this.nCurrEveStartIndex}`);
                }
            // }
        }
    }
    /**
     * 发送事件:为了个别模块需要利用错误码来处理逻辑，所以增加一个不定参数
     * @param eventName 
     * @param e 
     */
    public dispathEventWith(eventName:string, e:DataToUiEvent):void{
        this.dispatchEvent(eventName, e);
    }

    /**
     * 删除 eventName 事件
     * @param eventName 
     * @param handlToRemove 
     */
    public removeEventFast(eventName:string, handlToRemove:any):void{
        if(this.listeners.hasOwnProperty(eventName)){
            delete this.listeners[eventName];
        }
    }
    /**
     * 删除事件监听
     * @param handleToRemove 
     */
    public removeEventListener(handleToRemoveId:string):boolean{
        var isFound:boolean = false;
        for(const eventName in this.listeners){
            isFound = this.removeEventListenersByName(eventName, handleToRemoveId);
            if(isFound){
                break;
            }
        }
        return isFound;
    }

    /**
     * 删除事件监听
     * @param eventName 
     * @param handleToRemoveId 
     * @returns 
     */
    public removeEventListenersByName(eventName:string, handleToRemoveId:string):boolean{
        var isFound:boolean = false;
        var listenersForGEvent = this.listeners[eventName];
        if(null != listenersForGEvent){
            for(const handleIndex in listenersForGEvent){
                if(handleIndex == handleToRemoveId){
                    //
                    if(this.EVENT_DEBUG > 1){
                        console.log(`[GEvent] removeEventListener() - remove listener [${handleIndex}] for GEvent ${eventName}`);
                    }
                    //
                    delete this.listeners[eventName][handleIndex];
                    isFound = true;
                    break;
                }
                //
                if(isFound){
                    break;
                }
            }
        }
        return isFound;
    }

    /**
     * 根据 Tag 删除事件监听
     * @param tagToRemove 
     */
    public removeEventListenersByTag(tagToRemove:any):void{
        for(const eventName in this.listeners){
            var listenersForGEvent = this.listeners[eventName];
            for(const handleIndex in listenersForGEvent){
                if(listenersForGEvent[handleIndex][1] == tagToRemove){
                    delete this.listeners[eventName][handleIndex];
                }
            }
        }
    }

    // public removeEventListenersByName(eventName:string):void{
    // }

    // public removeAllEventListeners():void{
    // }

    /**
     * 判断事件监听是否存在
     * @param eventName 
     * @returns 
     */
    public hasEventListener(eventName:string):boolean{
        return this.listeners.hasOwnProperty(eventName);
    }
    /**
     * 打印堆
     */
    public DumpAllEventListeners():void{
        console.log("---- GEvent:dumpAllEventListeners() ----")
        for(const eventName in this.listeners){
            console.log(`-- GEvent: ${eventName}`);
            // 
            var listenersForGEvent = this.listeners[eventName];
            for(const handlerIndex in listenersForGEvent){
                var arr = listenersForGEvent[handlerIndex];
                console.log(`--     listener:${arr[0]} , handle: ${arr[1]}`);
            }
        }
    }
}

